Głównym zamierzeniem tych zajęć jest wypracowanie i przyswojenie sposobów krytycznej analizy tekstów, wypowiedzi oraz zbiorów danych. Przez analizę krytyczną rozumiemy tutaj między innymi umiejętność rozstrzygnięcia, czy materiał poddawany analizie nie jest wewnętrznie sprzeczny, czy zawiera stwierdzenia, których prawdziwość bądź fałszywość jesteśmy w stanie ustalić, czy jest najogólniej mówiąc wiarygodny. Spróbujemy ustalić czy istnieją schematy godne trwałego przyswojenia, którymi możemy posłużyć się przy analizie krytycznej?
Być może najważniejszym zadaniem analizy krytycznej jest ustalenie wartości analizowanego materiału. Znaczenie tego zadania wynika stąd, że materiał (np. praca naukowa, opracowanie dla klienta), uznany za wartościowy, staje się podstawą kolejnych wniosków. Może posłużyć do wytworzenia nowych materiałów, ale także podjęcia działań, których skutki zależą od ustaleń materiału źródłowego. Nieznaczny błąd popełniony na początku może doprowadzić do niezamierzonych, katastrofalnych skutków w przyszłości. Z drugiej strony, powinniśmy pamiętać, że materiał zawierający błędy może okazać się niezwykle wartościowy ze względu na jakieś ustalenia. Ostatecznie nawet z "fałszywych" przesłanek może wynikać prawdziwy i cenny wniosek. Np. pierwsza teoria rozchodzenia się ciepła przyjmowała, że ciepło jest niesione przez nieważką substancję $-$ cieplik $-$ rozchodzącą się w ciałach. W ciałach gorących jest jej po prostu więcej. Teoria cieplika nie wytrzymała próby czasu, ale równanie rozchodzenia się ciepła, znalezione w oparciu o tę teorię, uznawane jest za prawdziwe. Co więcej, nawet jeśli przyszła teoria ciepła odrzuci je, to pozostanie ono przedmiotem dociekań matematyków i przedstawicieli nauk ścisłych. Samo równanie i jego konsekwencje należą do wiedzy pewnej. Inaczej rzecz się ma z jego interpretacją.
Odszukaj w internecie materiały: raporty, wpisy, artykuły na temat gazu ziemnego. Ustal, do jakich celów jest wykorzystywany w gospodarce. Im więcej zastosowań gazu znajdziesz, tym lepiej.
Czy wzrost cen gazu ziemnego może mieć wpływ na ceny chleba? Odpowiedź uzasadnij, biorąc pod uwagę ustalone przez Ciebie gospodarcze zastosowania gazu.
Odszukaj tabele przedstawiające zmiany cen gazu w ostatnich latach w Ameryce Płn. i Europie. Poszukaj podobnych tabel dla nawozów amonowych. Porównaj i wyciągnij wnioski.
Oczekuję odpowiedzi na piśmie do 25 października.
Odpowiedzi powinny być zwięzłe, najlepiej w punktach. Rzeczy istotne powinny być wyróżnione (np. za pomocą kolejności - "ważniejsze najpierw"). Źrodła informacji powinny być podane.
Celem wykładu nie jest refleksja nad analizą, lecz analiza jako taka. Dlatego też będziemy unikać konstrukcji teoretycznych na korzyść praktyki. To znaczy, będziemy starali się, poprzez praktykę, doskonalić oszczędne sposoby analizy i argumentowania. Podkreślmy, że chodzi nam o sposoby oszczędne. Nie mają one podstawowego znaczenia, gdy np. analizujemy zbiór danych o małej złożoności, jednak wraz ze wzrostem złożoności oszczędność (analizy) ma znaczenie podstawowe.
Prawniczka ze swoim przyjacielem wracali z domku letniskowego. Przejeżdżając przez wieś potrącili dziecko, jak się okazało śmiertelnie. Natychmiast zatrzymali samochód, wysiedli z niego i wezwali policję. W obecności policji prawniczka zeznała, że samochód prowadził jej przyjaciel, ten natomiast zeznał, że prowadziła właścicielka auta, prawniczka. Innych świadków zdarzenia nie było. Jakie było rozstrzygniecie sądu?
Chodzi jedynie o odgadnięcie orzeczenia sądu o winie bądź niewinności uczestników zdarzenia.
Na brzozie rosną cztery gruszki a na sośnie dwie. Ile jest gruszek na drzewach?
W pewnych zakładach cukierniczych wytwarzano czekoladę pełną w tabliczkach 100 gramowych. Zgodnie z normą zakładową masa tabliczki musi się mieścić w granicach 95 $\div$ 105 gram. Zakłady kupiły nową maszynę, umożliwiającą tłoczenie tabliczek czekolady z dwuprocentową dokładnością, to znaczy, jeśli nastawimy maszynę na gramaturę $x$, to otrzymana tabliczka może mieć wagę o dwa procent większą, bądź dwa procent mniejszą niż $x$. Maszyna przetwarza 5 ton czekolady dziennie.
Zanim przejdziesz do obliczeń, podaj sposób oszacowania, czy gra jest "warta świeczki".
I na marginesie, co oznacza litera $\rm\large e$, umieszczana na produktach zwykle w pobliżu wagi lub objętości produktu? (Na niektórych produktach bywa pomijana.)
Przyjmijmy, że praktyka systematycznego niedoważania tabliczek czekolady, nawet jeśli ich gramatura mieści się w przedziale 95 $\div$ 105, jest poważnym wykroczeniem. Czy umiałbyś podać sposób wykrycia takiej praktyki?
Platforma Anaconda powstała z myślą o obróbce danych. Składa się na nią wiele programów i bibliotek. Platforma jest stale rozwijana. Umożliwia pracę z językami programowania Python, R i Julia. Te trzy języki mają podstawowe znaczenie dla analityka danych.
wejść na stronę projektu Anaconda
W przypadku, gdy ma się ograniczone zasoby pamięci można zainstalować okrojoną wersję platformy zwaną Miniconda. Wtedy interesujące nas pakiety dołącza się za pomocą pakietu Conda służącego do zarządzania środowiskami, bibliotekami oraz zależnościami. W miejsce Condy możemy też posługiwać się programem graficznym Anaconda Navigator (AN) . Instaluje się on automatycznie w przypadku, gdy zdecydujemy się na pełną wesję Anacondy. Możemy też go doinstalować za pomocą Condy.
Użyteczne ściągi dotyczące Anacondy oraz Condy można znaleźć tutaj ściąga1 (Anaconda Cheat Sheet) i tutaj ściąga2.
Olbrzymi zbiór ściąg odnoszących się do wszelkich programów oraz pakietów można znaleźć tutaj.
Będziemy posługiwali się głównie notatnikiem Jupyter Lab. Za jego pośrednictwem będziemy wykonywali opisy i analizy, a czasami pisali i uruchamiali niewielkie programy.
Można też posługiwać się starszą wersją notatnika Jupyter Notebook.
Jupyter wykorzystuje interaktywną powłokę IPython. Dzięki niej możemy na przemian kod pisać i natychmiast wykonywać. Jupyter umożliwia więcej: stworzenie całego interaktywnego dokumentu, gotowego do publikacji w sieci, czy odczytania za pomocą przeglądarki, w którym może się znaleźć tak tekst jak i wykresy, tabele, zdjęcia a nawet filmy.
Jest kilka sposobów uruchomienia Jupyter Lab (Notebook):
Ćwiczenie. Z notatnikami Jupyter można także pracować w ogóle nie instalując platformy Anaconda. Proszę się z tą możliwością zapoznać samodzielnie, jeśli ktoś jest zainteresowany.
Obok Pythona znajdującego się w dystrybucji Anaconda bądź Miniconda, dobrze jest zainstalować najnowszą wersję Pythona ze strony programu. Program instalacyjny nie wymaga większej uwagi, jednak dobrze w trakcie instalacji zaznaczyć okienko Add Python 3.9 to PATH. Dzięki temu będziemy mogli uruchamiać Pythona z wiersza poleceń lub terminala PowerShell, jednak nie jest to konieczne. Każdemu natomiast zaleca się przejrzenie znajdującego się w dokumentacji przewodnika po Pythonie - Python tutorial. W przewodniku omówione są zagadnienia niezbędne do posługiwania się Pythonem w analizie danych.
Jupyter ma trzy rodzaje okien: markdown, code, raw. W oknach markdown sporządzamy opisy, redagujemy treść. Okna code służą do pisania programów, zaś raw, do pisania tekstu nieobrobionego. Tekstem nieobrobionym możemy np. zapisać jakiś algorytm. Ten akapit zapisany jest w oknie markdown. Następny jest programem. Jeśli program chcemy wykonać, to klikamy myszą na okno i wciskamy kombinację klawiszy Shift+Enter.
for i in range(5): # drukujemy kwadraty pierwszych pięciu liczb naturalnych począwszy od 0
print(i**2)
for i in range(1,7): #drukujemy sześciany pierwszych sześciu liczb naturalnych począwszy od 1 print(i**3)
Zauważmy, że okna markdown i raw są nienumerowane, zaś code i owszem. Dlaczego?
2+2 # dodałem dwie liczby
3*4 # pomnożyłem
320/133 # podzieliłem
# A teraz wykonam skomplikowaną operację:
((3-7)/(4+2)-((3+1)/(16+7)+((3/7)/19)/20 +1))*34
$(\frac{3-7}{4+2}-(\frac{3+1}{16+7}+\frac {\frac{\frac 3 7} {19}}{20} +1)) \cdot 34$
(-4/6-(4/23 +(3/(19*140)+1)))*34
# Jeszcze mogę potęgować:
2**(1/3)
$2^{\frac 1 3}$
# A teraz dwie operacje na liczbach całkowitych:
33//7, 33%7
$m\% k$ oznacza więc resztę z dzielenia $m$ przez $k$, zaś $m//k$ oznacza wynik z dzielenia z resztą $m$ przez $k$ z pominięciem reszty.
type(3), type(3.5), type(4/10), type(10//4)
x=2.5
y=22.3
z=x*y
z
z**2
z**3
print(z**2)
print(z**3)
z = z**2
ćma=z
ćma
a_b=ćma
a_b
x == y
x <= y
x < y
Dowolne ciągi znaków Unicode wydzielone za pomocą cudzysłowów ' ' bądź " ".
# Przykład
'Wart Pac pałaca, "a pałac" Paca.'
"Wart Pac pałaca, a pałac Paca."
'ala',' ','ma kota'
pac='Wart Pac pałaca, a pałac Paca. '
(2)*pac
10*pac
pac*2
pac**2
type(pac)
kac='Ma kaca Pac i Pac ma kaca.'
pac+kac
str([1,2,3,4,5])
z=12
'Wiek = ' + str(z)
kac
len(kac) #funkcja len liczy ile jest znaków w łańcuchu
len(kac+pac)
kac[1:6]
kac[3:19] #podsłowo, począwszy od litery o numerze 3 (to będzie czwarta, bo zaczynamy od 0), do litery o numerze 18.
'Schizofrenia'[2:6]
kac[5:-7]
mac = kac[:]
mac==kac #pytanie o równość
mac = mac+' Tralabomba'
mac
mac==kac #powtórne pytanie o równość
mac!=kac #pytanie o różność!
kac < mac
type(kac)
help(str)
ddd='isafdr Ga'
ddd.islower()
mac
cmac=mac.capitalize()
cmac
mac
cmac
cmac.capitalize()
mac.upper()
mac.lower()
mac.upper()+mac.lower()
mac.partition('Pac')
mac.replace('Pac', 'Bach')
Listy to podstawowy sposób organizacji danych (struktura danych) w Pythonie.
[1,2,3,4,'a' ,[1,2,[3]]] #przyład
Jak widać, lista może zawierać liczby, łańcuchy a także inne listy (może być zagnieżdżona).
x, y=[1,2,3], [31,31,33,55]
z=x+y
z
2*z
z*2
z*z
print((2*x+3*y)*5)
[1,2,3]+[]
str(list('abcd'))
list(
"['a', 'b', 'c', 'd']")
[[[],[]],[[]],[]]
z=3
z
z=[1, 2, 3, 31, 31, 33]
print(z)
len(z)
z[2], z[3]
z[6]
z[1:4]
z[:4]
z[3:]
z[3:10]
v=[[1,2,'a'],[4,5,6],[7,8,9],[10,11,12]]
v[2]
v[2][1]
a=[1,2,3]
b=[7,2,3]
a.extend(b)
a
a.sort()
a
u=[]
for x in v:
for y in x:
u.append(y) # u=u+[y], u+=[y]
u
Ćwiczenie. Sporządź listę kwadratów pierwszych stu liczb naturalnych (zaczynamy od 0!).
Rozwiązanie. Instrukcja wygląda podobnie jak w przypadku zbiorów: $K=\{x^2\colon x\in\{0,\ldots, 99\}\}$. Jednak zamiast $\{0,\ldots, 99\}$ w Pythonie piszemy: $\texttt{range(100)}$; zamiast $x^2\colon x\in$, w Pythonie piszemy: $\texttt{x**2 for x in}$. Otrzymamy
K=[x**2 for x in range(100)] # Nam chodzi o listę, a nie o zbiór, więc zapisujemy w nawiasach kwadratowych.
print(K)
Gdybyśmy mieli życzenie sporządzić listę trzydziestu kolejnych kwadratów począwszy od kwadratu liczby 7, to musielibyśmy zmienić iterator na $\texttt{range(7, 37)}$:
[x**2 for x in range(7, 37)]
Ćwiczenie. Sporządź listę $L$ kwadratów liczb nieparzystych nieprzekraczających 100.
Rozwiązanie. Zbiór takich liczb moglibyśmy określilić tak: $L=\{x^2\colon x\in \{0,\ldots, 99\}, \text{o ile $x$ jest nieparzysta}\}$. W Pythonie zrobimy to bardzo podobnie:
L=[x**2 for x in range(100) if x%2==1] #liczby nieparzyste to te, których reszta z dzielenia przez 2 daje 1
print(L)
Opisaną procedurę nazywamy filtrowaniem: dopisaliśmy warunek, który $x$ musi spełniać (ma być nieparzysty) by element, w tym wypadku $x^2$, był zaliczony do $L$.
print(L)
345%2==1, 344%2==1, 344%2==0
Instrukcja to polecenie przekształcenia jakichś danych, często przechowywanych w postaci listy, łańcucha itp. Jeśli sposób wykonania przekształcenia zależy od dodatkowych warunków, to mówimy o instrukcji warunkowej. W Pythonie zarezerwowano odpowiednie słowa służące do tworzenia takich instrukcji, np.: $\texttt{if, elif, else}$.
wiek=input('Ile masz lat? ')
wzrost=input('Ile mierzysz? ')
waga=input('Ile ważysz?')
if int(wiek) >= 45:
print("Jak zuważyłeś, nazwa naszej placówki to 'Klinika Młodych'. Ludzi w Twoim wieku nie przyjmujemy.")
elif int(wzrost)>185:
print("Skąd mamy wziąć łóżko odpowiednie do Twojego wzrostu. Szukaj innego miejsca.")
elif int(waga)>45:
print("Obawiamy się, że nasze racje żywnościowe mogą nie być dla Ciebie wystarczające. Musiałbyś odżywiać się we własnym zakresie.")
else:
print("Proszę o stawienie się w naszym zakładzie za dwa tygodnie")
wiek=input('Ile masz lat? ')
wzrost=input('Ile mierzysz? ')
waga=input('Ile ważysz?')
if int(wiek) >= 45:
print("Jak zuważyłeś, nazwa naszej placówki to 'Klinika Młodych'. Ludzi w Twoim wieku nie przyjmujemy.")
elif int(wzrost)>185:
print("Skąd mamy wziąć łóżko odpowiednie do Twojego wzrostu. Szukaj innego miejsca.")
if int(waga)>45:
print("Obawiamy się, że nasze racje żywnościowe mogą nie być dla Ciebie wystarczające. Musiałbyś odżywiać się we własnym zakresie.")
else:
print("Proszę o stawienie się w naszym zakładzie za dwa tygodnie")
Instrukcji tej użyliśmy kilkukrotnie. Za każdym razem odwoływaliśmy się do iteratorów $\texttt{range}$. Można także wykonywać tę instrukcję na każdym ciągu jak łańcuch, czy lista.
Przykład użycia $\texttt{for}$ na łańcuchu.
w='abcdefghijklmnopqrstuvwxyz'
i=0
for x in w:
print(x, i)
i=i+1
Przykład użycia instrukcji $\texttt{for}$ na liście.
v=[[1,2],[4,5],[9,10]]
V=[]
for x in v:
V=V+x
V
Iterator $\texttt{range}$ może być także użyty z określonym skokiem: $\texttt{range(m,n, s)}$. Liczba startowa $m$ kolejne $m+s$, $m+2s$, itd. Ostatnia liczba w ciągu jest mniejsza niż $n$ i zarazem największą postaci $m+ks$.
for i in range(-4, 11, 3):
print(i)
range(-4,11,3) # Obiekt range nie zajamuje pamięci, jak np. lista.
list(range(-4,11,3)) # Funkcja list(x) tworzy z obiektu x listę, o ile to możliwe.
list('abcdef')
i=-4 #porównaj z range(-4,11,3)
while i<11:
print(i)
i=i+3
Ćwiczenie Dwa pierwsze wyrazy ciągu F.: 1, 1. Kolejne są sumami dwu poprzedzających. Wyznacz pierwsze trzydzieści wyrazów tego ciągu. $a_0$, $a_1$ - dane; $a_{n+2}=a_n+a_{n+1}$
Rozwiązanie.
x=[1] #wyrazy zbierzemy na liście x
a=1
b=1
i=0
while i<=28:
[a,b]=[b,a+b]
x=x+[a]
i=i+1
#Sprawdzenie:
print(len(x))
print(x)
Listy, podobnie jak łańcuchy i inne klasy mają swoje swoje metody. Można je wywołać:
help(list)
a=[12,35,46,35]
a.remove(7)
a
Można też zajrzeć do podrozdziału 5.1 Poradnika (Tutorial).
Listy są obiektami mutowalnymi, tzn. możemy zmieniać zawartość listy bez zmiany jej nazwy; np. dołączyć dodatkowy element za pomocą metody 'append': Jeśli L -dana lista, p - dowolna dana, którą chcemy dołączyć, to $\texttt{L.append(p)}$ tworzy listę, której nazwa to nadal L, ale lista ma na końcu dołączony element p.
L=[1,7,'a']
p='kura ma pióra'
L.append(p)
L
Ćwiczenie. Dane:
A=[[1],2,[3]]
B='stek'
Jaki będzie rezultat wykonania następujących instrukcji? W szczególności, czy listy Cytata i A będą różne, czy takie same?
Cytata=A
A.append(B)
print(A)
print(Cytata)
I odrobinę więcej komplikacji. Jak będzie wyglądała lista P powstała w wyniku zastosowania kolejnych operacji?
x=[1,2,3,4]
P=[x for i in range(7)]
P[3][3]='zdziwiony?'
x, P
Wniosek $P$ jest listą tożsamych list. Zmiana jednej, wywołuje identyczną zmianę pozostałych. $P[3]$ jest inną etykietą (aliasem) listy $x$.
Jeśli chcemy, by listy były identyczne lecz nietożsame, musimy sporządzić ich (płytkie) kopie:
x=[1,2,3,4]
R=[x.copy() for i in range(7)]
R[3][3]='niezdziwiony'
R
(proszę przeszukać dokumentację lub dostępne podręczniki w celu uzyskania dodatkowych informacji)
Ćwiczenie. Sprawdzić, czy na liście znajduje się pozycja 'czerwony' i wydrukować komunikat.
magazyn=[1,2,3,4,'biały',1,13,'czerwony', 'niebieski', 'buk', 'leń', 'czerwony', 23, 14, 'XXXX', 'czerwony', 'pp','biały']
for x in magazyn:
if x=='czerwony':
print("Na magazynie znajduje się 'czerwony'")
for x in magazyn:
if x=='czerwony':
print("Na magazynie znajduje się 'czerwony'")
break
Ćwiczenie. Wykonać poniższą instrukcję. Następnie wyłączyć linię continue i wykonać:
for num in range(13):
if num%2==0:
print("Znaleziono liczbę parzystą", num)
continue
print("Znaleziono liczbę", num)
I jeszcze podobne ćwiczenie:
Ćwiczenie. Wykonać poniższą instrukcję
for num in range(13):
if num%2==0:
print("Znaleziono liczbę parzystą", num)
pass
print("Znaleziono liczbę", num)
Jeśli jakiś fragment programu powtarza się, a zmieniają się jedynie dane, warto stworzyć funkcję, która będzie obsługiwała wszystkie takie przypadki. Tym samym będziemy mogli wielokrotnie wykorzystać ten sam fragment kodu.
Przykład. Chcemy wyznaczyć wszystkie ciągi 0-1 długości 7. Wtedy lepiej napisać funkcję pozwalającą na wyznaczenie wszystkich ciągów długości $n\ge 1$.
def zerojeden(n):
x=[[0],[1]]
for i in range(1, n):
x=[[0]+u for u in x]+[[1]+ u for u in x]
return(x)
$\texttt{return(x)}$ oznacza, że wywołanie funkcji $\texttt{zerojeden(n)}$ tworzy listę $x$ złożoną ze wszystkich ciągów 0-1 długości $n$. Oczywiście $n$ musi mieć konkretną wartość. Lista ta jest drukowana automatycznie:
zerojeden(3)
Jeśli chcemy drukowania uniknąć, musimy nadać liście etykietę:
z3=zerojeden(3)
Ćwiczenie. Ciąg Fibonacciego może startować z jakiejkolwiek pary wartości $a$, $b$. Określ funkcję wyznaczającą pierwszych $n$ wyrazów ciągu Fibonacciego o wyrazach początkowych $a$, $b$.
def fib(a=1,b=1, n):
L=[a]
for i in range(n-1):
a, b=b, a+b
L.append(a)
return(L)
fib(2,-1,10)
Jeśli jakieś wartości startowe będą używane najczęściej, możemy argumenty startowe zdeklarować z domyślnymi wartościami. Wtedy będziemy mogli je pominąć przy wywoływaniu funkcji.
def fib2(n, a=1,b=1):
L=[a]
for i in range(n-1):
a, b=b, a+b
L.append(a)
return(L)
fib2(10,2,-1)
Proszę zwrócić uwagę na zmianę kolejności argumentów. Argumenty o wartościach domyślnych deklarujemy zawsze na końcu.
fib2(8)
fib2(10,2,-1)
Za argumentami funkcji mogą się kryć dowolne dane, także listy, łańcuchy bądź krotki.
Krotki są podobne to list, jednak są niemutowalne. Na poziomie praktycznym oznacza to, że nie mają, w zasadzie, metod umożliwiających ich modyfikację bez zmiany nazwy. Np.
x=(1,2,3,4,5)
y=[1,2,3,4,5]
x[3],y[3]
x=1,2,3,4,5
x
y[3]='a co tam'
y
# lista y uległ modyfkacji
# to samo dla x
x[3]='a co tam'
# Listy i krotki można zamieniać jedne w drugie za pomocą wbudowanych funkcji list(), tuple():
list(x), tuple(list(x))
# Skoro krotki są niemutowalne, to czy mogą zawierać mutowalne elementy?
X=([1],[2,[3]], 35)
X[1][0]=3
X
x=tuple()
y=(1,)
x=()
type(x)
Więcej na temat krotek w dokumentacji. Metody możemy poznać za pomocą $\texttt{help(tuple)}$.
x?
Ćwiczenie. Zbudować funkcję, która przeplata wyrazy dwu list. Listy powinny być równej długości, a jeśli nie są, to powinniśmy otrzymać stosowny komunikat.
def przeplatacz(u,v):
a,b=len(u), len(v)
if a!=b: #obsługa wyjątków
print('Dane mają niezgodny format.')
else:
L=[]
for i in range(a):
L.append(u[i])
L.append(v[i])
return L
u,v=[1,2,3], ['a','b','c']
L=przeplatacz(u,v)
L
v=tuple(v)
L=przeplatacz(u,v)
L
przeplatacz('Bigda','Dyzma')
Komentarz. Jak widać, jeśli typy danych nie są w definicji funkcji zadeklarowane, to można użyć innych typów niż te, dla których funkcję domyślnie tworzyliśmy. W wielu językach np. Pascal, C, niepodobna określić funkcji bez wyraźnego określenia typu.